import 'dart:convert';
import 'dart:io';

import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:flutter_shop/generated/json/base/json_convert_content.dart';
import 'package:flutter_shop/pages/base/common_result.dart';
import 'package:flutter_shop/pages/common/login/entity/base_info.dart';
import 'package:flutter_shop/utils/utils.dart';

///请求baseurl
//const String BASE_URL = Utils.isProd ? "http://mockapi.shandaiguanjia.com/mockapi/mock/1/" : "http://mockapi.shandaiguanjia.com/mockapi/mock/1/";
const String BASE_URL = Utils.isProd ? "https://wxmini.baixingliangfan.cn/baixing/wxmini/" : "https://wxmini.baixingliangfan.cn/baixing/wxmini/";

///是否代理
const bool IS_PROXY = false;

///代理IP,青花瓷抓包ip和端口
const String PROXY_IP = "192.168.1.200:8090";

///连接超时时间
const int CONNECT_TIMEOUT = 10000;

///接收数据的最长时间
const int RECEIVE_TIMEOUT = 3000;

///content_type
const String CONTENT_TYPE = Headers.formUrlEncodedContentType;

///Title:对dio网络请求封装 <br/>
///Description: <br/>
///author:xiemiao <br/>
///date: 2020-02-17 <br/>
///version 1.0 <br/>
class Http {
  factory Http() => _getInstance();

  static Http _instance;

  static Http _getInstance() {
    if (_instance == null) {
      _instance = Http._internal();
    }
    return _instance;
  }

  Dio _dio;
  BaseOptions defOption;

  Http._internal() {
    defOption = BaseOptions(
      contentType: CONTENT_TYPE,
      connectTimeout: CONNECT_TIMEOUT,
      receiveTimeout: RECEIVE_TIMEOUT,
      responseType: ResponseType.plain,
      //设置返回数据是字符串
      baseUrl: BASE_URL,
    );
    _dio = new Dio(defOption);
    _dio.interceptors.add(CommonInterceptor());

    (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
      //非生产环境才设置代理
      if (!Utils.isProd && IS_PROXY) {
        // config the http client
        client.findProxy = (uri) {
          //proxy all request to localhost:8888
          return "PROXY $PROXY_IP";
        };
      }
      //https证书校验
      client.badCertificateCallback = (X509Certificate cert, String host, int port) {
        return true;
      };
      // you can also create a HttpClient to dio
      // return HttpClient();
    };
  }

  ///post请求,CommonResult接收
  Future<CommonResult<T>> post<T>(String path, {data}) async {
    try {
      Response response = await _dio.post(path, data: data);
      return Future(() => CommonResult<T>.fromJson(response.data));
    } catch (error) {
      return Future.error(error);
    }
  }

  ///get请求,CommonResult接收
  Future<CommonResult<T>> get<T>(String path, {data}) async {
    try {
      Response response = await _dio.get(path, queryParameters: data);
      return Future(() => CommonResult<T>.fromJson(response.data));
    } catch (error) {
      return Future.error(error);
    }
  }

  ///post请求,T接收,针对没有固定格式的返回
  Future<T> postT<T>(String path, {data}) async {
    try {
      Response response = await _dio.post(path, data: data);
      return Future(() => JsonConvert.fromJsonAsT<T>(response.data));
    } catch (error) {
      return Future.error(error);
    }
  }

  ///get请求,T接收,针对没有固定格式的返回
  Future<T> getT<T>(String path, {data}) async {
    try {
      Response response = await _dio.get(path, queryParameters: data);
      return Future(() => JsonConvert.fromJsonAsT<T>(response.data));
    } catch (error) {
      return Future.error(error);
    }
  }
}

///常规拦截器
class CommonInterceptor extends Interceptor {
  ///请求成功的code
  final success = "0";

  ///取返回结果里的code
  final String codeKey = "code";

  ///取返回结果里的msg
  final String msgKey = "message";

  @override
  Future onRequest(RequestOptions options) {
    //添加请求头
    String token = BaseInfo.getToken();
    if (Utils.strIsNotEmpty(token)) {
      options.headers['token'] = token;
    }

    return super.onRequest(options);
  }

  @override
  Future onResponse(Response response) {
    //配置里已设置responseType: ResponseType.plain,返回数据是字符串,这里解析成Map再赋值给Response
    //之所以这样做,是因为在请求http接口时,dio会自动解析data数据为Map,但是在请求https接口时,它没有自动解析成Map,所以这里只有自己转换了
    var res = json.decode(response.data);
    response.data = res;

    var code = res[codeKey];
    String msg = res[msgKey];

    if (code == null) {
      return super.onResponse(response);
    } else if (code != success) {
      return Future.error(DioError(
        response: response,
        error: "$msg[$code]",
        type: DioErrorType.RESPONSE,
      ));
    } else {
      return super.onResponse(response);
    }
  }
}
